package RobertsCoalition.types;

import iteration.RecursiveAccess;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import population.Population;

import combinations.Combinations;

import utils.Util;

import RobertsCoalition.Coalition;
import RobertsCoalition.CoalitionFormation;

public class OneAttributeCoalition implements CoalitionType{

	//int attributeIndex;
	int maximumDisjunctiveSize;
	int[] dimensionSizes;
	Population population;
	HashMap<Integer, Combinations> combinationSchemes;
	
	public OneAttributeCoalition(CoalitionFormation coalitionFormation,
			HashMap<Integer, Combinations> combinationSchemes
			//, int attributeIndex
			){
		//this.attributeIndex = attributeIndex;
		this.maximumDisjunctiveSize = coalitionFormation.getMaximumDisjunctiveSize();
		this.dimensionSizes = coalitionFormation.getDimensionSizes();
		this.population = coalitionFormation.getPopulation();
		this.combinationSchemes = combinationSchemes;
	}
	
	//this is the case of coalitions in which only
	//one attribute is used to specify the coalition.
	//all combinations of values for that attribute are
	//legal except for the empty set, a coalition with no people,
	//and the full set, a coalition with everyone in it
	@Override
	public List<Coalition> getCoalitions(){
		List<Coalition> coalitions = new Vector<Coalition>();
		//pick an attribute
		int length = population.getDimensionSizes().length;
		for(int i = 0; i < length; i++){
			Vector<Coalition> coalitionsWithAttributeSet =
				getAllCoalitionsByDeterminingAtttribute(i);
			coalitions.addAll(coalitionsWithAttributeSet);
		}
		return coalitions;
	}
	
	public Vector<Coalition> getAllCoalitionsByDeterminingAtttribute(int attributeIndex) {
		//calculate all combinations of attribute values for the given attribute
		List<List<Integer>> combinations;
		if(maximumDisjunctiveSize == -1)
			combinations = combinationSchemes.get(attributeIndex).getCombinations(dimensionSizes[attributeIndex]);
		else
			combinations = combinationSchemes.get(attributeIndex).getCombinationsUpToSize(
				dimensionSizes[attributeIndex], maximumDisjunctiveSize);
		
		Vector<Coalition> coalitions = new Vector<Coalition>();
		
		//for each combination in the list of combinations
		for(List<Integer> combination : combinations){
			//ignore the empty and full sets
			if(combination.size() == dimensionSizes[attributeIndex]
			  || combination.size() == 0                                     
			) continue;
			List<int[]> sectorsInvolved = new Vector<int[]>();
			List<int[]> sectorsReducedRepresentation = new Vector<int[]>();	
			//for each attribute index present in a given combination
			for(int attributeValue : combination){
				//get a representation of a part of a coalition that
				//consists of all cross sections that have a given attribute
				//set to some value and arbitrary values for all other attributes
				//this representation will have a nonnegative number in one element of
				//an array of size dimensionSizes and -1 in other positions
				//-1 indicates "all possible values" or "don't care" 
				int[] indices = 
					Util.getIndexArrayWithOneValue(dimensionSizes.length, attributeIndex, attributeValue);
				//use that representation to generate all the involved cross sections explicitly
				List<int[]> coalitionSubList = 
					RecursiveAccess.generateAllPermutations(indices, dimensionSizes);
				//add up all sub-coalition cross sections to cumulative coalition cross section list
				sectorsInvolved.addAll(coalitionSubList);
				sectorsReducedRepresentation.add(indices);
			}
			//add coalition given by a combination of categories 
			//within an attribute to the total list of coalitions
			Coalition coalition = new Coalition(population, sectorsInvolved, sectorsReducedRepresentation);
			coalitions.add(coalition);
		}
		return coalitions;
	}

}
